package com.douma.practical_3.external_sort;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.util.Comparator;
import java.util.PriorityQueue;

/**
 * 抖码课堂，专注中国程序员基础内功修炼
 * 官网：douma-tech.com
 * 公众号：资深程序员老汤
 *
 * @作者 : 老汤
 */
public class _3_ExternalSorter {

    public void mergeSort(String dirName) throws Exception {
        File dir = new File(dirName);
        File[] children = dir.listFiles();

        // 1. 初始化一个最小堆，大小就是有序小文件的个数
        // 堆中的每个节点存放每个有序小文件对应的输入流
        PriorityQueue<BufferedIterator> minHeap =
                new PriorityQueue<>(children.length,
                        new Comparator<BufferedIterator>() {
            @Override
            public int compare(BufferedIterator o1, BufferedIterator o2) {
                // 按照每个有序文件中的下一行数据对所有文件输入流进行排序
                // 整数小的输入文件流放在堆顶
                Integer i1 = Integer.valueOf(o1.currNum());
                Integer i2 = Integer.valueOf(o2.currNum());
                return i1.compareTo(i2);
            }
        });

        // 2. 将所有有序文件的输入流包装成 BufferedIterator 放入到堆中
        for (File file : children) {
            BufferedReader br = FileIOUtils.getReader(file.getAbsolutePath());
            BufferedIterator buf = new BufferedIterator(br);

            // 要有数据才放入到堆中，否则关闭流
            if (buf.hasNext()) {
                minHeap.add(buf);
            } else {
                buf.close();
            }
        }

        BufferedWriter bw = FileIOUtils.getWriter("data\\sort\\sorted_nums.txt");
        // 3. 拿出堆顶的数据，并写入到最终排序的文件中
        while (!minHeap.isEmpty()) {
            BufferedIterator heapTopBuffer = minHeap.poll();
            bw.write(heapTopBuffer.currNum());
            bw.newLine();

            // 如果拿出来的输入流中还有数据的话，那么将这个输入流再一次添加到堆中，
            if (heapTopBuffer.hasNext()) {
                minHeap.add(heapTopBuffer);
            } else {
                heapTopBuffer.close();
            }
        }

        FileIOUtils.closeWriter(bw);
    }

    public static void main(String[] args) throws Exception {
        String dirName = "data\\sort\\sorted_data\\";

        new _3_ExternalSorter().mergeSort(dirName);
    }

}

